#include "PlatformManager.h"
#include "GraphicsManager.h"
#include "PScheduler.h"

#include <boost/filesystem.hpp>

namespace Proton 
{
	namespace Managers
	{
		using namespace boost::filesystem;

		PlatformManager::PlatformManager()
		{
			pScheduler = nullptr;
			pGraphics = nullptr;
			windowHandle = nullptr;

			// initialize logging system
			logStream.open("log.txt");			
			log("log created");
			log("------------------------");
		}


		PlatformManager::~PlatformManager(void)
		{
			logStream.close();
		}

		void PlatformManager::initialize(HINSTANCE _hInstance, LPCSTR lpCmdLine, int iCmdShow, PScheduler* _pScheduler, GraphicsManager* _pGraphics)
		{
			pGraphics = _pGraphics;
			pScheduler = _pScheduler;

			WNDCLASS wc;

			wc.style			= CS_BYTEALIGNCLIENT | CS_HREDRAW | CS_VREDRAW;
			wc.lpfnWndProc		= msgRouter;
			wc.cbClsExtra		= 0;
			wc.cbWndExtra		= 0;
			wc.hInstance		= (HINSTANCE)GetModuleHandle(NULL);
			wc.hIcon			= LoadIcon(wc.hInstance, MAKEINTRESOURCE(103));
			wc.hCursor			= LoadCursor(NULL, IDC_ARROW);
			wc.hbrBackground	= (HBRUSH )GetStockObject(WHITE_BRUSH);
			wc.lpszMenuName		= nullptr;
			wc.lpszClassName	= L"ProtonWindow";

			RegisterClass(&wc);

			RECT wr = {0, 0, pGraphics->getWindowWidth(), pGraphics->getWindowHeight()};
			AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, false);

			windowHandle = CreateWindow(L"ProtonWindow", L"ProtonWindow",
				WS_OVERLAPPEDWINDOW, 0, 0, wr.right - wr.left, wr.bottom - wr.top,
				NULL, NULL, wc.hInstance, this);
			
			ShowWindow(windowHandle, SW_SHOW);
		}

		HWND PlatformManager::getWindowHandle()
		{ 
			return windowHandle;
		}

		void PlatformManager::releaseResources()
		{
			//delete all MMO's

		}

		void PlatformManager::messageBox(LPCWSTR title, LPCWSTR message)
		{
			MessageBox(windowHandle, message, title,  MB_ICONINFORMATION | MB_OK);
		}
		
		bool PlatformManager::syncReadFile(PFile* pPFile)
		{			
			FILE* handle;

			fopen_s(&handle, pPFile->getFilePath().string().c_str(), "rb");
			
			if (handle && pPFile->getDataPtr() == nullptr)
			{
				pPFile->setDataSize(file_size(pPFile->getFilePath()));
				pPFile->setDataPtr(new char[pPFile->getDataSize()]);

				fread(pPFile->getDataPtr(), 1, pPFile->getDataSize(), handle);

				int err = ferror(handle);

				fclose(handle);

				if(err == 0)
					return true;
				else
					return false;
			}
			else
			{
				// file not empty
				return false;
			}
		}

		bool PlatformManager::syncWriteFile(PFile* pPFile)
		{
			if(!pPFile->getFilePath().empty() && pPFile->getDataPtr() != nullptr && pPFile->getDataSize() != 0)
			{
				FILE* handle;
				fopen_s(&handle, pPFile->getFilePath().string().c_str(), "w");

				fwrite(pPFile->getDataPtr(), 1, pPFile->getDataSize(), handle);
				fclose(handle);
				return true;
			}
			else
				return false;
		}


		LRESULT CALLBACK PlatformManager::msgRouter(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
		{
			if (message == WM_CREATE)
				::SetWindowLong(hWnd, GWL_USERDATA, long((LPCREATESTRUCT(lParam))->lpCreateParams));

			PlatformManager* dest = (PlatformManager*)::GetWindowLong(hWnd, GWL_USERDATA);

			if (dest)
				return dest->wndProc(hWnd, message, wParam, lParam);

			return DefWindowProc(hWnd, message, wParam, lParam);
		}

		LRESULT PlatformManager::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
		{
			switch(message)
			{
			case WM_DESTROY:
				{
					PostQuitMessage(0);
					return 0;
				} break;
			}

			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		
		void PlatformManager::log(std::string message)
		{
			logStream << message.c_str() << "\n";
		}

		void PlatformManager::log(const char* message)
		{
			logStream << message << "\n";
		}
	}
}